package com.huaxin.dss2.data.dao;

import com.huaxin.dss2.data.bean.DataValue;
import com.huaxin.dss2.data.bean.properties.HxDssProperties;
import com.huaxin.dss2.data.dao.base.BaseRDBDataDao;
import com.huaxin.dss2.data.exception.jdbc.DataSourceNotFoundException;
import com.huaxin.dss2.message.exception.SaveRealDataException;
import java.sql.BatchUpdateException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @author : luqing
 * @date : 2018/6/27 16:06
 */

@Component("mysqlDataDao")
@Slf4j
public class MySQLDataDao extends BaseRDBDataDao {

    private OrgDataSource orgDataSource;



    @Autowired
    public void setOrgDataSource(OrgDataSource orgDataSource) {
        this.orgDataSource = orgDataSource;
    }

    @Override
    public void init() {
        log.info("初始化MySQL数据源");
        orgDataSource.refreshOrgDataSource();
    }

    @Override
    public void save(String stationCode, List<DataValue> saveList, Date dataDate)
        throws DataSourceNotFoundException, SaveRealDataException, SQLException {
        //查找分库后缀
        String dataOrgCode = findDataOrgCode(stationCode);
        if (StringUtils.isEmpty(dataOrgCode)) {
            log.info("没有查找到站点-->{}", stationCode);
            return;
        }
        //后缀小写
        dataOrgCode = dataOrgCode.toLowerCase();
        log.info("{}查找到企业库名称-->{}",stationCode, dataOrgCode);
        //这里加入 昆山二供逻辑  不分库
        //是否自动分库  false时不分库，所有站点在同一个库
        JdbcTemplate jdbcTemplateData = orgDataSource.getJdbcTemplate("collect".toLowerCase());
        //获取对应库Template
       // JdbcTemplate jdbcTemplateData = orgDataSource.getJdbcTemplate(dataOrgCode.toLowerCase());
        //如果Template不存在
        if (jdbcTemplateData == null) {//数据库不存在时
            log.info("jdbcTemplate_data is null ****end");
            //建表(表存在时刷新源) 建库
            jdbcTemplateData = createTable(dataOrgCode);
            //建表分区
            alterTablePart(jdbcTemplateData, dataOrgCode);
        }else{
            log.info("{}开始存储",stationCode);
            try {
            String tableName="datadb_"+dataOrgCode.toLowerCase();
            String tableexists="SELECT count(*) FROM information_schema.TABLES WHERE table_name = '"+tableName+"';";
            int count=jdbcTemplateData.queryForObject(tableexists,Integer.class);
            if(count==0){ //表不存在时直接  创库创表
                //建表(表存在时刷新源) 建库
                jdbcTemplateData = createTable(dataOrgCode);
                //建表分区
                alterTablePart(jdbcTemplateData, dataOrgCode);
            }

                this.batchUpdate(jdbcTemplateData,saveList,dataDate);
            } catch (Exception e) {
                e.printStackTrace();
                log.info("保存数据时异常",e.getMessage());
                log.error("保存数据时异常",e);
                if (e.getCause() instanceof BatchUpdateException) {
                    if ("23000".equals(((BatchUpdateException) e.getCause()).getSQLState())) {
                        //唯一建约束错误,跳过
                        log.warn("数据库中已经存在此数据,跳过");
                    } else if ("HY000".equals(((BatchUpdateException) e.getCause()).getSQLState())) {
                        log.error("{}数据保存异常", stationCode, e);
                        alterTablePart(jdbcTemplate, dataOrgCode);
                    }
                } else {
                    log.error(e.getMessage(), e);
                    throw new SaveRealDataException(e);
                }
            } finally {
                log.info("站点{} save方法执行", stationCode);
            }
            log.info("站点{}数据入库写入完毕！", stationCode);

        }
    }


    /**
     * 根据分库规则进行分库
     * @param jdbcTemplateData 数据源
     * @param dataOrgCode 分库规则
     */
    public static void alterTablePart(JdbcTemplate jdbcTemplateData, String dataOrgCode) {
        //最后一天进入下一个月分区
        Long partMillis = System.currentTimeMillis() + 60 * 60 * 24 * 1000;
        SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd");
        try {
            //是否自动分库  false时不分库，所有站点在同一个库
/*            Boolean isCreateDatabaseName=hxDssProperties.getisCreateDatabaseName();
            String  CreateDatabaseName=hxDssProperties.getCreateDatabaseName();*/
            //获取分区时间月最后一天
            String lastDateSql = "SELECT (LAST_DAY(DATE('" + sim.format(partMillis) + "'))-0)";
            String lastDate = jdbcTemplateData.queryForObject(lastDateSql, String.class);
            String partitionSql="";
            String tableName="datadb_" + dataOrgCode.toLowerCase();
            partitionSql = "alter table datadb_collect."+tableName+" add partition (partition p" + lastDate + " values  less than (TO_DAYS(" + lastDate + ")))";
     /*       if(!isCreateDatabaseName) { //不分库时，分表
              String tableName="datadb_" + dataOrgCode;
                partitionSql = "alter table datadb_" + CreateDatabaseName + "."+tableName+" add partition (partition p" + lastDate + " values  less than (TO_DAYS(" + lastDate + ")))";
            }else{//分库 分表时的逻辑
                //新增分区
                 partitionSql = "alter table datadb_" + dataOrgCode + ".c_datavalue add partition (partition p" + lastDate + " values  less than (TO_DAYS(" + lastDate + ")))";
            }*/



            jdbcTemplateData.getDataSource().getConnection().prepareStatement(partitionSql).execute();
            log.info("新增分区{}完成", dataOrgCode);
        } catch (SQLException e) {
            log.error("增加新分区{}时出错", dataOrgCode, e);
        }
    }

    private JdbcTemplate createTable(String dataOrgCode) throws DataSourceNotFoundException {

        Long partMillis = System.currentTimeMillis() + 60 * 60 * 24 * 1000;
        SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd");
        String lastDateSql = "SELECT (LAST_DAY(DATE('" + sim.format(partMillis) + "'))-0)";
        //是否自动分库  false时不分库，所有站点在同一个库
        String sqlString="CREATE DATABASE IF NOT EXISTS datadb_collect  DEFAULT CHARACTER SET utf8 ;";

        jdbcTemplate.execute(sqlString);
        JdbcTemplate jdbcTemplateData=null;
        jdbcTemplateData = orgDataSource.getJdbcTemplate("collect");
        if(jdbcTemplateData==null){ //数据库存在时则 不进行任何刷库操作
            orgDataSource.refreshOrgDataSource();
            jdbcTemplateData = orgDataSource.getJdbcTemplate("collect");
        }
        String tableName="";
        //同一个库 表名按照 站点编码来
        tableName="datadb_"+dataOrgCode.toLowerCase();
/*        if(!isCreateDatabaseName) { //不分库时，分表
        }else{
            jdbcTemplateData= orgDataSource.getJdbcTemplate(dataOrgCode);
            tableName="c_datavalue";
        }*/

        String lastDate = jdbcTemplateData.queryForObject(lastDateSql, String.class);

        String createString = " CREATE TABLE IF NOT EXISTS " + tableName + " (" +
            "  `orgCode` VARCHAR(45) NOT NULL," +
            "  `dataItemId` INT(11) NOT NULL," +
            "  `dataCode` VARCHAR(45) NOT NULL," +
            "  `textValue` VARCHAR(45) DEFAULT NULL," +
            "  `numValue` DECIMAL(16,5) DEFAULT NULL," +
            "  `dataDate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," +
            "  `inputDate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," +
            "  UNIQUE KEY `uk_orgCode_dataItemId_dataCode_dataDate` (`orgCode`,`dataItemId`,`dataCode`,`dataDate`)" +
            ") "+
            "ENGINE=InnoDB DEFAULT CHARSET=utf8 " +
            "PARTITION BY range(to_days(dataDate))(" +
            "PARTITION p"+ lastDate +" VALUES less than (TO_DAYS("+lastDate+"))" +
            ");";


        jdbcTemplateData.execute(createString);
        return jdbcTemplateData;
    }

    /**
     * 获取分库后缀
     * @param stationCode 站点id
     * @return 分库后缀字段
     */
    private String findDataOrgCode(String stationCode) {
        String sql = hxDssProperties.getSql().getDatabaseSuffixSql();
        return jdbcTemplate.queryForObject(sql, String.class, stationCode);
    }

    private Boolean isSaveTime(JdbcTemplate jdbcTemplateData) throws DataSourceNotFoundException {
        Boolean flag = false;
        Map<String, Object> s = jdbcTemplateData.queryForMap("SELECT MAX(dataDate) AS tim FROM c_datavalue ORDER BY dataDate DESC;");
        if (s.get("tim") != null && s.size() > 0) {
            String time = String.valueOf(s.get("tim"));
            log.info("数据库最新时间-->" + time);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date;
            try {
                date = sdf.parse(time);
                log.info("间隔时间-->" + (System.currentTimeMillis() - date.getTime()));
                long interval = 5;
                if ((System.currentTimeMillis() - date.getTime()) / (1000 * 60) > interval) {
                    flag = true;
                }

            } catch (ParseException e) {
                e.printStackTrace();
            }

        } else {
            flag = true;
        }
        System.out.print("存储flag-->" + flag);
        return flag;
    }

    @Override
    protected void batchUpdate(JdbcTemplate jdbcTemplate, List<DataValue> saveList, Date dataDate)
        throws Exception {
        //String tableName = hxDssProperties.getDataValueTableName();
        //是否自动分库  false时不分库，所有站点在同一个库
/*        String tableName="datadb_"+dataOrgCode;*/
        DataValue dataValue = saveList.get(0);
        String[] fullDataCode = dataValue.getDataCode().split("_");
        jdbcTemplate.batchUpdate(
                "INSERT INTO datadb_" + fullDataCode[0].toLowerCase() +"(orgCode,dataItemId,dataCode, numValue,dataDate,inputDate) VALUES(?,?,?,?,?,?)",
                super.batchPreparedStatementSetter(saveList,dataDate));

/*        Boolean isCreateDatabaseName=hxDssProperties.getisCreateDatabaseName();
        if(!isCreateDatabaseName) { //不分库时，分表
            tableName="datadb_"+dataOrgCode;
            jdbcTemplate.batchUpdate(
                    "INSERT INTO " + tableName +"(orgCode,dataItemId,dataCode, numValue,dataDate,inputDate) VALUES(?,?,?,?,?,?)",
                    super.batchPreparedStatementSetter(saveList,dataDate));
        }else{
            jdbcTemplate.batchUpdate(
                    "INSERT INTO " + tableName +"(orgCode,dataItemId,dataCode, numValue,dataDate,inputDate) VALUES(?,?,?,?,?,?)",
                    super.batchPreparedStatementSetter(saveList,dataDate));
        }*/

    }
}
